#pragma once
#include "Common.h"

#include <string>
#include <ctime>
#include <cstring>

using std::string;

// 定长内存池
// template<size_t N>
// class ObjectPool
//{};

template <class T>
class ObjectPool
{
public:
	T *New()
	{
		T *obj = nullptr;
		// 优先把还回来的内存块对象重复利用
		if (_freelist)
		{
			obj = (T *)_freelist;
			_freelist = *(void **)obj;
		}
		else
		{
			// 剩余内存不够一个对象大小时，则重新开大块空间64kb
			if (_leftBytes < sizeof(T))
			{
				_memory = (char *)malloc(64 * 1024);
				_leftBytes = 64 * 1024;
				if (_memory == nullptr)
				{
					throw std::bad_alloc();
				}
			}
			obj = (T *)_memory;
			size_t objSize = sizeof(T) < sizeof(void *) ? sizeof(void *) : sizeof(T);
			_memory += objSize;
			_leftBytes -= objSize;
		}
		// 定位new
		new (obj) T;

		return obj;
	}
	void Delete(T *obj)
	{
		// 显示调用析构函数
		obj->~T();
		// 头插
		if (_freelist == nullptr)
		{
			_freelist = obj;
			//*(int*)obj = nullptr;//(32位)
			*(void **)obj = nullptr; //(64位 32位 二级指针都可以)
		}
		else
		{
			*(void **)obj = _freelist;
			_freelist = obj;
		}
	}

private:
	size_t _leftBytes = 0; // 大块内存在切分过程中的剩余字节数
	char *_memory;		   // 指向大块内存的指针
	void *_freelist;	   // 还回过程中的自由链表的头指针
};

// 测试分别用new和ObjectPool的效率
void TestObjectPool()
{
	ObjectPool<string> pool;

	// 用new
	clock_t begin1 = clock();
	for (size_t i = 0; i < 1000000; i++)
	{
		string *str = new string;
		delete str;
	}
	clock_t end1 = clock();
	cout << "new: " << end1 - begin1 << endl;

	// 用ObjectPool
	clock_t begin2 = clock();
	for (size_t i = 0; i < 1000000; i++)
	{
		string *str = pool.New();
		pool.Delete(str);
	}
	clock_t end2 = clock();
	cout << "ObjectPool: " << end2 - begin2 << endl;
}
